package cn.qj.ymcc.service.impl;

import cn.qj.ymcc.api.OrderFeignApi;
import cn.qj.ymcc.domain.AlipayInfo;
import cn.qj.ymcc.domain.PayFlow;
import cn.qj.ymcc.domain.PayOrder;
import cn.qj.ymcc.dto.AlipayNotifyDto;
import cn.qj.ymcc.dto.ApplyDto;
import cn.qj.ymcc.dto.UpdateOrderStatusDto;
import cn.qj.ymcc.exception.GlobleBusinessException;
import cn.qj.ymcc.mapper.PayOrderMapper;
import cn.qj.ymcc.result.JSONResult;
import cn.qj.ymcc.service.IAlipayInfoService;
import cn.qj.ymcc.service.IPayFlowService;
import cn.qj.ymcc.service.IPayOrderService;
import com.alibaba.fastjson.JSONObject;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.common.models.AlipayTradeCancelResponse;
import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.util.ParameterFormatter;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.Valid;
import javax.validation.constraints.Size;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;


/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author whale
 * @since 2025-07-31
 */
@Service
@Slf4j
public class PayOrderServiceImpl extends ServiceImpl<PayOrderMapper, PayOrder> implements IPayOrderService {

    @Autowired
    private IAlipayInfoService alipayInfoService;
    @Autowired
    private PayOrderMapper payOrderMapper;
    @Autowired
    private IPayFlowService payFlowService;
    @Autowired
    private OrderFeignApi orderFeignApi;

    /**
     * 异步回调
     *
     * @param alipayNotifyDto
     * @return
     */
    @Override
    public String notifyPay(@Valid AlipayNotifyDto alipayNotifyDto) {
        //1.参数校验   使用@Valid注解 然后再Dto里面的字段加不为空等等
        try {
            //2.验签 防止数据被更改
            Map<String,String> parameters = JSONObject.parseObject(JSONObject.toJSONString(alipayNotifyDto), Map.class);
            Boolean aBoolean = Factory.Payment.Common().verifyNotify(parameters);
            if(!aBoolean){
                return "fail";
            }
            //3. 商家需要验证该通知数据中的 out_trade_no 是否为商家系统中创建的订单号。
            PayOrder payOrder = checkPayOrder(alipayNotifyDto.getOut_trade_no());
            if(payOrder == null){
                return "fail";
            }
            // 4. 判断 total_amount 是否确实为该订单的实际金额（即商家订单创建时的金额）。
            if(!StringUtils.equals(payOrder.getAmount().toString(),alipayNotifyDto.getTotal_amount())){
                return "fail";
            }
            //5. 校验通知中的 seller_id（或者 seller_email）是否为 out_trade_no 这笔单据的对应的操作方（有的时候，一个商家可能有多个 seller_id/seller_email）。
            //6. 验证 app_id 是否为该商家本身。没有app_id TODO

            //7.自己的业务
            //7.1修改订单状态 增加流水记录  三个参数 订单编号  订单状态  更新时间
            Date date = new Date();
            Integer payStatus = 0;
            if(alipayNotifyDto.getTrade_status().equals(AlipayNotifyDto.TRADE_CLOSED)){
                payStatus = 2;
            }
            if(alipayNotifyDto.getTrade_status().equals(AlipayNotifyDto.TRADE_SUCCESS)
            || alipayNotifyDto.getTrade_status().equals(AlipayNotifyDto.TRADE_FINISHED)){
                payStatus = 1;
            }
            payOrderMapper.updateStatusByOrderNo(alipayNotifyDto.getOut_trade_no(),date,payStatus);
            //增加流水记录
            PayFlow payFlow = new PayFlow();
            payFlow.setNotifyTime(date);
            payFlow.setSubject(alipayNotifyDto.getSubject());
            payFlow.setTradeStatus(alipayNotifyDto.getTrade_status());
            payFlow.setCode(alipayNotifyDto.getCode());
            payFlow.setMsg(alipayNotifyDto.getMsg());
            payFlow.setPaySuccess(payStatus==1?true:false);
            payFlow.setTotalAmount(new BigDecimal(alipayNotifyDto.getTotal_amount()));
            payFlow.setResultDesc(
                    "支付状态为：" + (alipayNotifyDto.getTrade_status().equals(AlipayNotifyDto.TRADE_SUCCESS)||
                            alipayNotifyDto.getTrade_status().equals(AlipayNotifyDto.TRADE_FINISHED)
                            ? "支付成功"
                            : "支付失败")+
                    "，支付金额为：" + alipayNotifyDto.getTotal_amount());
            payFlowService.insert(payFlow);
            //7.2修改订单状态 ====== 订单服务
            UpdateOrderStatusDto updateOrderStatusDto = new UpdateOrderStatusDto();
            updateOrderStatusDto.setOrderNo(alipayNotifyDto.getOut_trade_no());
            updateOrderStatusDto.setStatusOrder(payStatus);
            JSONResult jsonResult = orderFeignApi.updateOrderStatus(updateOrderStatusDto);
            log.info("订单状态更新结果：{}", jsonResult);
            return "success";
            //7.3t_course_user_learn增加一条记录 ======= 课程服务
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "fail";
    }

    /**
     * 取消订单
     *
     * @param orderNo
     */
    @Override
    public void cancelOrder(String orderNo) {
        //退款


        if(!StringUtils.isEmpty(orderNo)){
            try {
                AlipayTradeCancelResponse cancel = Factory.Payment.Common().cancel(orderNo);
                log.info("取消订单结果：{}",cancel);
            } catch (Exception e) {
                e.printStackTrace();
                log.info("取消订单失败：{}",e.getMessage());
            }
        }
    }

    /**
     * 根据订单号查询订单状态 支付宝那边的
     *
     * @param orderNo
     */
    @Override
    public String checkPayStatus(String orderNo) {
        try {
            AlipayTradeQueryResponse query = Factory.Payment.Common().query(orderNo);
            return query.getHttpBody();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "error";

    }

    /**
     * 根据订单编号 查询订单是否生成
     *
     * @param orderNo
     * @return
     */
    @Override
    public PayOrder checkPayOrder(String orderNo) {
        //校验订单编号是否为空
        if(StringUtils.isEmpty(orderNo)){
            throw new GlobleBusinessException("订单号不存在");
        }
        Wrapper<PayOrder> ww = new EntityWrapper<>();
        ww.eq("order_no",orderNo);
        PayOrder payOrder = selectOne(ww);
        return payOrder;
    }

    /**
     * 申请支付
     *
     * @param applyDto
     * @return
     */
    @Override
    public String apply(ApplyDto applyDto) {
        String returnUrl = applyDto.getCallUrl();
        String orderNo = applyDto.getOrderNo();
        Integer payType = applyDto.getPayType();

        //查询数据库中的表 t_alipay_info
        List<AlipayInfo> alipayInfos = alipayInfoService.selectList(null);
        AlipayInfo alipayInfo = alipayInfos.get(0);
        // 1. 设置参数（全局只需设置一次）
        Factory.setOptions(getOptions(alipayInfo));

        //根据订单编号查询支付单
        Wrapper<PayOrder> ww = new EntityWrapper<>();
        ww.eq("order_no",orderNo);
        PayOrder payOrder = selectOne(ww);
        try {
            AlipayTradePagePayResponse response = Factory.Payment.Page().pay(
                    payOrder.getSubject(),
                    orderNo,
                    payOrder.getAmount().toString(),
                    returnUrl);
            // 3. 处理响应或异常
            if (ResponseChecker.success(response)) {
                System.out.println("调用成功");
                return response.getBody();
            } else {
                System.err.println("调用失败，原因：" + response.getBody());
            }
        } catch (Exception e) {
            System.err.println("调用遭遇异常，原因：" + e.getMessage());
            throw new RuntimeException(e.getMessage(), e);
        }
        return null;
    }



    public Config getOptions(AlipayInfo alipayInfo) {
        Config config = new Config();
        config.protocol = alipayInfo.getProtocol();
        config.gatewayHost = alipayInfo.getGatewayHost();
        config.signType = alipayInfo.getSignType(); //加密类型
        config.appId = alipayInfo.getAppId();
        // 为避免私钥随源码泄露，推荐从文件中读取私钥字符串而不是写入源码中
        config.merchantPrivateKey = alipayInfo.getMerchantPrivateKey();
        //注：证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径，优先从文件系统中加载，加载失败后会继续尝试从CLASS_PATH中加载
        config.alipayPublicKey = alipayInfo.getAlipayPublicKey();
        //可设置异步通知接收服务地址（可选）
        config.notifyUrl = alipayInfo.getNotifyUrl();
        return config;
    }
}
